package cn.gyxy.Aspect;


import cn.gyxy.pojo.Guanli;
import cn.gyxy.pojo.Rizhi;
import cn.gyxy.service.RizhiService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.net.UnknownHostException;


@Slf4j
@Aspect
@Component
public class LogAspect {




    //一  切入点 ：多种方式  我们这里使用注解方式
//    @Pointcut("bean(*service)")  //bean形式切入点
//    @Pointcut("within(cn.gyxy.service.impl.*)")
    @Pointcut("@annotation(cn.gyxy.Aspect.Bsrizhi)")//注解全类名
    public void dolog() {
    } //承载切入点注解pointcut

    //二 通知方法  好几种  我们这里使用功能最强大的环绕通知
    @Around("dolog()")
    public Object doArount(ProceedingJoinPoint joinPoint) throws Throwable {
        long t1 = System.currentTimeMillis();
        log.info("start {}", t1);
        try {
            Object result = joinPoint.proceed();//执行目标方法
            long t2 = System.currentTimeMillis();
            log.info("end {}", t2);
            saveUserLog(joinPoint, t2 - t1);
            return result;
        } catch (Throwable e) {
            log.error("error {}", e.getMessage());
            throw e;
        }

    }

    @Autowired
    private RizhiService rizhiService;

    private void saveUserLog(ProceedingJoinPoint joinPoint, long time) throws NoSuchMethodException, JsonProcessingException, UnknownHostException {
        //一获取用户ip
        String ip = GetIp.getIp().toString();
        //二获取登录用户用户SecurityUtils,

        Guanli guanli= (Guanli) SecurityUtils.getSubject().getPrincipal();  //无法实现有问题
        //三获取执行方法的对象（反射)

        Class<?> targetClass = joinPoint.getTarget().getClass();

        //四、获取目标对象中的方法
        MethodSignature ms = (MethodSignature) joinPoint.getSignature();
        Method targetMethod = targetClass.getDeclaredMethod(ms.getName(), ms.getParameterTypes());

        //5获取方法上的注解,进而获取注解中operation属性的值。
      Bsrizhi bsrizhi = targetMethod.getAnnotation(Bsrizhi.class);
        String operation = bsrizhi.operation();
        //6获取方法信息  全类+方法名
        String method = targetClass.getName() + "." + targetMethod.getName();

        //7获取调用方法的参数信息,且转化为json格式
        String params = new ObjectMapper().writeValueAsString(joinPoint.getArgs());
        //8将需要的日志信息封装到日志对象
        Rizhi rizhi = new Rizhi();
        rizhi.setUsername(guanli.getUsername());//无法获取用户，用ip代替先
        rizhi.setMethod(method);
        rizhi.setParams(params);
//将对象封装到数据库
        rizhiService.insertRizhi(rizhi);

    }


}




